// 属性装饰器
// 1、基本语法
// target：对于静态属性来说值是类，对于实例属性来说值是类的原型对象
// propertyKey：属性名
function demo0518(target:object,propertyKey:string){
    console.log('demo',target,propertyKey);
}
class Test0518{
    // 对实例属性使用装饰器时，target是类的原型对象
    @demo0518 name:string
    @demo0518 age:number
    @demo0518 static school:string
    // 对静态属性使用装饰器时，target是该calss类
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
}
// 2、关于属性遮蔽(不是属性装饰器的功能，是为什么要有属性装饰器的原因)
// 如下代码中，当构造器中的this.age = age试图在实例上赋值是，实际上是调用了原型上age属性的set方法

class Demo0518 {
    name:string
    age:number
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
}

// 当new一个Demo0518实例在Object.defineProperty()前执行时，打印的p0518的数据是:"{name:'xxx',age:'xxx'}"
// const p0518 = new Demo0518('张三',18)
// console.log('p1',p0518)
let value = 130
Object.defineProperty(Demo0518.prototype,'age',{
    get() {
        return value
    },
    set(val) {
        value = val
    },
})
// 当new一个Demo0518实例在Object.defineProperty()前执行时，打印的p0518的数据是:"{name:'xxx'}",age属性没有了
const p0518 = new Demo0518('张三',18)
console.log('p1',p0518);
// 原理：因为Object.defineProperty方法在原型对象上添加了一个age属性，于是构造器里的this.age = age执行的时候，会在Demo0518身上查询age属性，本着有则改之，无则添加
//于是在Demo0518实例对象上没有找到age属性，但是在原型对象上找了age属性，于是在原型对象上修改了age的值
// 而Object.defineProperty()写在new实例之后不存在属性遮蔽是因为，this.age = age执行的时候是在实例对象上添加了age属性

// 3、应用举例
// 需求：定义一个State属性装饰器，来监视属性的修改

function State(target:object,propertyKey:string){
    let key = `__${propertyKey}`
    // 利用__xxx，将属性值绑定在每个对应的实例对象上
    Object.defineProperty(target,propertyKey,{
        get() {
            return this[key]
        },
        set(newValue) {
            console.log(`${propertyKey}的最新值为:${newValue}`);
            this[key] = newValue
        },
        enumerable:true,    // 可枚举性：是否参与循环
        configurable:true    //可配置性
    })    
}
class PersonTest0518{
    @State name:string
    @State age:number
    constructor(name:string,age:number){
        this.name = name
        this.age = age
    }
}

const a0518 = new PersonTest0518('夜南',18)
a0518.age= 20
